package org.springblade.modules.repair.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateException;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.repair.dto.statistical.*;
import org.springblade.modules.repair.entity.MaintainPlanUserDayCount;
import org.springblade.modules.repair.entity.MaintainSignCalendar;
import org.springblade.modules.repair.enums.MaintainPlanContentEnum;
import org.springblade.modules.repair.enums.TaskStatusEnum;
import org.springblade.modules.repair.mapper.WorkStatisticalMapper;
import org.springblade.modules.repair.service.IMaintainPlanContentService;
import org.springblade.modules.repair.service.IMaintainSignCalendarService;
import org.springblade.modules.repair.service.IWorkStatisticalService;
import org.springblade.modules.repair.service.MaintainPlanUserDayCountService;
import org.springblade.modules.repair.vo.MaintainPlanUserDayCountVO;
import org.springblade.modules.repair.vo.statistics.*;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 工单作业统计分析服务类
 * @Author ysq
 * @Date 2022/8/24
 **/
@Slf4j
@Service
@AllArgsConstructor
public class WorkStatisticalServiceImpl implements IWorkStatisticalService {

	private final WorkStatisticalMapper workStatisticalMapper;

	private final IMaintainSignCalendarService maintainSignCalendarService;

	private final MaintainPlanUserDayCountService maintainPlanUserDayCountService;

	private final IUserService userService;


	/**
	 * 工单日历表
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkCalendarVO> chart1(WorkCalendarDTO params) {
		DateTime date = null;
		try {
			date = DateUtil.parse(params.getYearMonth(),"yyyy-MM");
		} catch (DateException e) {
			throw new RuntimeException(e);
		}
		DateTime curDate = DateUtil.date();
		// 是否本月
		boolean isCurMonth = date.monthBaseOne() == curDate.monthBaseOne();
		DateTime start = DateUtil.beginOfMonth(date);
		DateTime end = DateUtil.endOfMonth(date);
		params.setBeginDate(start);
		params.setEndDate(end);
		List<DateTime> rangeDate = DateUtil.rangeToList(start, end, DateField.DAY_OF_YEAR);
//		List<WorkCalendarVO> workCalendarList = workStatisticalMapper.selectWorkCalendar(params, rangeDate);

		List<WorkCalendarVO> workCalendarList = new ArrayList<>(31);
		List<WorkOrderListVO> workOrderList = workStatisticalMapper.selectWorkOrderList(params);
		Map<String, List<WorkOrderListVO>> workOrderMap = workOrderList.stream().collect(Collectors.groupingBy(t -> t.getRecordDate()));
		for (DateTime itemDate : rangeDate) {
			String itemDateStr = DateUtil.format(itemDate, "yyyy-MM-dd");
			WorkCalendarVO workCalendarVO = new WorkCalendarVO();
			workCalendarVO.setDate(itemDateStr);
			if (workOrderMap.containsKey(itemDateStr)) {
				workCalendarVO.setOrderCount(workOrderMap.get(itemDateStr).stream().map(t -> t.getPlanId()).distinct().count());
				workCalendarVO.setUserCount(workOrderMap.get(itemDateStr).stream().map(t -> t.getUserId()).distinct().count());
			} else {
				workCalendarVO.setOrderCount(0L);
				workCalendarVO.setUserCount(0L);
			}
			workCalendarList.add(workCalendarVO);
		}

		Map<String, Integer> holidayMap = null;
		// 是否显示休息日
		boolean isShowHoliday = params.getIsShowHoliday();
		if (isShowHoliday) {
			List<MaintainSignCalendar> calendarList = maintainSignCalendarService.getMaintainSignCalendarByUserId(params.getUserIds().get(0), start, end);
			holidayMap = calendarList.stream().collect(Collectors.toMap(t -> DateUtil.format(t.getDate(), "yyyy-MM-dd"), t -> t.getHoliday()));
		}

		// 懒加载 用于存储月份的计划统计
		Map<String, Integer> planUserDayCountMap = null;
		for (WorkCalendarVO workCalendarVO : workCalendarList) {
			if (isShowHoliday && Func.isNotEmpty(holidayMap)) {
				workCalendarVO.setHoliday(holidayMap.get(workCalendarVO.getDate()));
			}

			// 当天实时运算
			if (isCurMonth && DateUtil.format(curDate, "yyyy-MM-dd").equals(workCalendarVO.getDate())) {
				WorkCalendarVO todayWorkCalendar = workStatisticalMapper.selectTodayWorkCalendar(params.getUserIds());
				workCalendarVO.setOrderCount(todayWorkCalendar.getOrderCount());
				workCalendarVO.setUserCount(todayWorkCalendar.getUserCount());
			}

			// 若工单数为0，需查询是否有任务
			if (workCalendarVO.getOrderCount() == 0) {
				if (DateUtil.compare(DateUtil.parse(workCalendarVO.getDate()), curDate, "yyyy-MM-dd") < 0) {
					if (planUserDayCountMap == null) {
						List<WorkCalendarTaskCountVO> planUserDayCountList = workStatisticalMapper.selectWorkCalendarTaskCount(params.getUserIds(),start, end);
						planUserDayCountMap = planUserDayCountList.stream().collect(Collectors.toMap(t -> t.getRecordDate(), t -> t.getPlanCount()));
					}
					workCalendarVO.setIsPlan(!planUserDayCountMap.containsKey(workCalendarVO.getDate()) ? false : planUserDayCountMap.get(workCalendarVO.getDate()) > 0);
				} else if (DateUtil.compare(DateUtil.parse(workCalendarVO.getDate()), curDate, "yyyy-MM-dd") == 0) {
					// 若为今天,查询今天以前未处理保养工单数
					long todayPlanCount = workStatisticalMapper.selectTodayPlanCount(params.getUserIds());
					workCalendarVO.setIsPlan(todayPlanCount > 0);
				}
			}
		}

		return workCalendarList;
	}

	/**
	 * 每日作业明细-维保员
	 * @param params
	 * @return
	 */
	@Override
	public List<DayWorkDetailVO> chart2(DayWorkDetailDTO params) {
		// 若为今天
		if (Func.isNotEmpty(params.getDate()) && DateUtil.compare(DateUtil.date(), params.getDate(), "yyyy-MM-dd") == 0) {
			return workStatisticalMapper.personalTodayWorkDetail(params);
		} else {
			return workStatisticalMapper.personalWorkDetail(params);
		}
	}

	/**
	 * 每日作业明细-按组
	 * @param params
	 * @return
	 */
	@Override
	public List<DeptDayWorkDetailVO> chart3(DeptDayWorkDetailDTO params) {
		List<DeptDayWorkDetailVO> workDetailVOList = new ArrayList<>();
		// 是否为今日
		boolean isToday = Func.equalsSafe(DateUtil.format(params.getDate(), "yyyy-MM-dd"), DateUtil.today());
		params.getDeptGroups().forEach(deptGroup -> {
			List<WorkTypeDetailVO>  workTypeDetailList = null;
			if (isToday) {
				workTypeDetailList = workStatisticalMapper.todayWorkTypeDetail(deptGroup.getUserIds());
			}else {
				workTypeDetailList = workStatisticalMapper.workTypeDetail(deptGroup.getUserIds(), null, params.getDate());
			}

			DeptDayWorkDetailVO deptDayWorkDetailVO = new DeptDayWorkDetailVO();
			deptDayWorkDetailVO.setDeptName(deptGroup.getDeptName());
			int totalWorkHour = workTypeDetailList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
			deptDayWorkDetailVO.setTotalWorkHour(totalWorkHour);
			Set<String> userSet = new TreeSet<>();
			workTypeDetailList.forEach(typeDetail -> {
				userSet.addAll(Func.toStrList(typeDetail.getUserStr()));
				if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					deptDayWorkDetailVO.setByOrderCount(typeDetail.getOrderCount());
					deptDayWorkDetailVO.setByUserCount(typeDetail.getUserCount());
					deptDayWorkDetailVO.setByWorkHour(typeDetail.getWorkHour());
					deptDayWorkDetailVO.setByDivUserWorkTime(typeDetail.getDivUserWorkTime());
				} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					deptDayWorkDetailVO.setWxOrderCount(typeDetail.getOrderCount());
					deptDayWorkDetailVO.setWxUserCount(typeDetail.getUserCount());
					deptDayWorkDetailVO.setWxWorkHour(typeDetail.getWorkHour());
					deptDayWorkDetailVO.setWxDivUserWorkTime(typeDetail.getDivUserWorkTime());
				} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) {
					deptDayWorkDetailVO.setPjOrderCount(typeDetail.getOrderCount());
					deptDayWorkDetailVO.setPjUserCount(typeDetail.getUserCount());
					deptDayWorkDetailVO.setPjWorkHour(typeDetail.getWorkHour());
					deptDayWorkDetailVO.setPjDivUserWorkTime(typeDetail.getDivUserWorkTime());
				}
			});
			// 合计作业人数
			long totalUserCount = userSet.stream().count();
			deptDayWorkDetailVO.setTotalUserCount(totalUserCount);
			deptDayWorkDetailVO.setTotalDivWorkHour(totalUserCount == 0 ? 0 : totalWorkHour / Func.toInt(totalUserCount));
			workDetailVOList.add(deptDayWorkDetailVO);
		});

		return workDetailVOList;
	}

	/**
	 * 每日作业明细-按人
	 * @param params
	 * @return
	 */
	@Override
	public List<DeptUserWorkDetailVO> chart4(DeptUserWorkDetailDTO params) {
		List<User> userList = userService.listByIds(params.getUserIds());
		Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getId(), t -> t.getRealName()));

		// 是否为今日
		boolean isToday = Func.equalsSafe(DateUtil.format(params.getDate(), "yyyy-MM-dd"), DateUtil.today());
		List<DeptUserWorkDetailVO> userWorkDetailVOList = new ArrayList<>();
		params.getUserIds().forEach(userId -> {
			List<WorkTypeDetailVO> workTypeDetailList = null;
			if (isToday) {
				// 若为今日
				workTypeDetailList = workStatisticalMapper.todayWorkTypeDetail(Arrays.asList(userId));
			}else {
				workTypeDetailList = workStatisticalMapper.workTypeDetail(Arrays.asList(userId), null, params.getDate());
			}

			DeptUserWorkDetailVO userWorkDetailVO = new DeptUserWorkDetailVO();
			userWorkDetailVO.setUserId(userId);
			userWorkDetailVO.setUserName(userMap.get(userId));
			int totalWorkHour = workTypeDetailList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
			userWorkDetailVO.setTotalWorkHour(totalWorkHour);
			workTypeDetailList.forEach(typeDetail -> {
				if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					userWorkDetailVO.setByOrderCount(typeDetail.getOrderCount());
					userWorkDetailVO.setByWorkHour(typeDetail.getWorkHour());
				} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					userWorkDetailVO.setWxOrderCount(typeDetail.getOrderCount());
					userWorkDetailVO.setWxWorkHour(typeDetail.getWorkHour());
				} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) {
					userWorkDetailVO.setPjOrderCount(typeDetail.getOrderCount());
					userWorkDetailVO.setPjWorkHour(typeDetail.getWorkHour());
				}
			});
			userWorkDetailVOList.add(userWorkDetailVO);
		});

		// 汇总 “全部”
		List<WorkTypeDetailVO> allWorkTypeDetailList = null;
		if (isToday) {
			// 若为今日
			allWorkTypeDetailList = workStatisticalMapper.todayWorkTypeDetail(params.getUserIds());
		}else {
			allWorkTypeDetailList = workStatisticalMapper.workTypeDetail(params.getUserIds(), null, params.getDate());
		}
		DeptUserWorkDetailVO userWorkDetailVO = new DeptUserWorkDetailVO();
		userWorkDetailVO.setUserName("全部");
		int totalWorkHour = allWorkTypeDetailList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
		userWorkDetailVO.setTotalWorkHour(totalWorkHour);
		allWorkTypeDetailList.forEach(typeDetail -> {
			if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
				userWorkDetailVO.setByOrderCount(typeDetail.getOrderCount());
				userWorkDetailVO.setByWorkHour(typeDetail.getWorkHour());
			} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
				userWorkDetailVO.setWxOrderCount(typeDetail.getOrderCount());
				userWorkDetailVO.setWxWorkHour(typeDetail.getWorkHour());
			} else if (typeDetail.getType() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) {
				userWorkDetailVO.setPjOrderCount(typeDetail.getOrderCount());
				userWorkDetailVO.setPjWorkHour(typeDetail.getWorkHour());
			}
		});
		userWorkDetailVOList.add(userWorkDetailVO);

		return userWorkDetailVOList;
	}

	/**
	 * 作业汇总（数量）-作业时长-维保员
	 * @param params
	 * @return
	 */
	@Override
	public PersonalWorkSummaryVO chart5(WorkStatisticalDTO params) {
		PersonalWorkSummaryVO personalWorkSummaryVO = new PersonalWorkSummaryVO();
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		if (!Func.isEmpty(workDayList)) {
			// 实际作业天数
			long workDayCount = workDayList.stream().map(t -> t.getRecordDate()).distinct().count();
			personalWorkSummaryVO.setWorkDayCount(workDayCount);
			if (workDayCount > 0) {
				// 累计作业时长
				int workTimeTotal = workDayList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
				personalWorkSummaryVO.setWorkTimeTotal(workTimeTotal);
				// 日均作业时长
				int divDayWorkTime = workTimeTotal/Integer.valueOf(String.valueOf(workDayCount));
				personalWorkSummaryVO.setDivDayWorkTime(divDayWorkTime);
			}
		}

		// 查询考勤日历
		List<MaintainSignCalendar> calendarList = maintainSignCalendarService.getMaintainSignCalendarByUserId(params.getUserIds().get(0), params.getBeginDate(), params.getEndDate());
		if (Func.isEmpty(calendarList)) {
			// 未加入考勤组
			personalWorkSummaryVO.setHolidayCount(-1);
		} else {
			personalWorkSummaryVO.setHolidayCount(calendarList.stream().filter(t -> t.getHoliday() == 1).count());
		}

		return personalWorkSummaryVO;
	}

	/**
	 * 作业汇总（数量）-作业时长-维保组长
	 * @param params
	 * @return
	 */
	@Override
	public LeaderWorkSummaryVO chart6(WorkStatisticalDTO params) {
		LeaderWorkSummaryVO leaderWorkSummaryVO = new LeaderWorkSummaryVO();
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		if (Func.isEmpty(workDayList)) {
			leaderWorkSummaryVO.setDivUserWorkDay(BigDecimal.ZERO);
			leaderWorkSummaryVO.setDivUserDayWorkTime(0);
			leaderWorkSummaryVO.setWorkTimeTotal(0);
			return leaderWorkSummaryVO;
		}

		// 作业人数
		long workUserCount = workDayList.stream().map(t -> t.getUserId()).distinct().count();
		leaderWorkSummaryVO.setWorkUserCount(workUserCount);

		//每人对应实际作业天数
		Map<Long, Long> userWorkDayMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getUserId(),
				Collectors.mapping(t -> t.getRecordDate(), Collectors.collectingAndThen(
					Collectors.toCollection(TreeSet::new),t -> t.stream().count())
				)
		));
		// 每人实际作业天数总和
		long workDayTotal = userWorkDayMap.entrySet().stream().collect(Collectors.summingLong(t -> t.getValue()));
		// 人均作业天数
		BigDecimal divUserWorkDay = new BigDecimal(workDayTotal).divide(new BigDecimal(workUserCount), 2, BigDecimal.ROUND_HALF_UP);
		leaderWorkSummaryVO.setDivUserWorkDay(divUserWorkDay);

		// 累计作业时长
		int workTimeTotal = workDayList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
		leaderWorkSummaryVO.setWorkTimeTotal(workTimeTotal);

		// 每天对应工作时长
		Map<String, Integer> dayWorkTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy-MM-dd"), Collectors.summingInt(t -> t.getWorkHour())));
		// 每天对应作业人数
		Map<String, Long> dayWorkUserCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy-MM-dd"),
			Collectors.mapping(t -> t.getUserId(), Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count()))
		));
		// 每天人均耗时
		Map<String, Integer> dayUserTimeMap = new HashMap<>(16);
		dayWorkTimeMap.forEach((key, value) -> {
			// 耗时
			int time = value / Convert.toInt(dayWorkUserCountMap.get(key));
			dayUserTimeMap.put(key, time);
		});
		// 总耗时
		int timeTotal = dayUserTimeMap.entrySet().stream().collect(Collectors.summingInt(t -> t.getValue()));
		/**
		 * 人均每日作业时长:
		 * 人均每日作业时长=每日人均作业时长总和÷实际作业天数;（每日指有作业日）；
		 * 每日人均作业时长=每日各人累计作业时长总和÷每日作业人数；（每日指有作业日）
		 */
		int divUserDayWorkTime = timeTotal / dayUserTimeMap.size();
		leaderWorkSummaryVO.setDivUserDayWorkTime(divUserDayWorkTime);

		return leaderWorkSummaryVO;
	}

	/**
	 * 作业汇总-整体趋势--作业时长
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart7(WorkStatisticalDTO params) {
		// 作业工单类型
		String[] initTypeArr = {String.valueOf(MaintainPlanContentEnum.MAINTAIN_BY.getId()), String.valueOf(MaintainPlanContentEnum.MAINTAIN_WX.getId()), String.valueOf(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())};
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		if (!Func.isEmpty(workDayList)) {
			int dimension = params.getDimension();
			if (dimension == 0) {
				// 日
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"),
						Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))));
			} else if (dimension == 1) {
				// 周
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
						}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
				));
			} else {
				// 月
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s月",DateUtil.format(date, "yyyy年M"));
					}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
				));
			}
		}

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 1);
	}

	/**
	 * 作业汇总-趋势对比--作业时长-按人
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart8(WorkStatisticalDTO params) {
		// 用户集合信息
		List<User> userList = userService.listByIds(params.getUserIds());
		Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getId(), t -> t.getRealName()));
		String[] initTypeArr = userList.stream().map(t -> t.getRealName()).toArray(String[]::new);
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), params.getType());
		if (!Func.isEmpty(workDayList)) {
			int dimension = params.getDimension();
			if (dimension == 0) {
				// 日
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"),
						Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))));
			} else if (dimension == 1) {
				// 周
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
					}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
				));
			} else {
				// 月
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s月",DateUtil.format(date, "yyyy年M"));
					}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
				));
			}
		}

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 1);
	}

	/**
	 * 作业汇总-趋势对比--作业时长-按组
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart9(WorkGroupStatisticalDTO params) {
		// 作业工单类型
		String[] initTypeArr = params.getDeptGroups().stream().map(t -> t.getDeptName()).toArray(String[]::new);
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);

		params.getDeptGroups().forEach(deptGroup -> {
			List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), deptGroup.getUserIds(), params.getType());
			if (!Func.isEmpty(workDayList)) {
				Map<String, BigDecimal> workDayTimeMap = null;
				int dimension = params.getDimension();
				if (dimension == 0) {
					// 日
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"),
							Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add)));
				} else if (dimension == 1) {
					// 周
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> {
							Date date = t.getRecordDate();
							return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
						}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
					);
				} else {
					// 月
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> {
							Date date = t.getRecordDate();
							return String.format("%s月",DateUtil.format(date, "yyyy年M"));
						}, Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getWorkHour()), BigDecimal::add))
					);
				}
				trendData.put(deptGroup.getDeptName(), workDayTimeMap);
			}
		});

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 1);
	}

	/**
	 * 初始化趋势图数据
	 * @param beginDate
	 * @param endDate
	 * @param dimension
	 * @return
	 */
	private Map<String, BigDecimal> initTrendChartData(Date beginDate, Date endDate, int dimension) {
		Map<String, BigDecimal> trendDataMap = new LinkedHashMap<>(32);
		if (dimension == 0) {
			// 日
			List<DateTime> rangeDate = DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				trendDataMap.put(DateUtil.format(date, "yyyy/M/d"), BigDecimal.ZERO);
			});
		} else if (dimension == 1) {
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!trendDataMap.containsKey(weekDate)) {
					trendDataMap.put(weekDate,BigDecimal.ZERO);
				}
			});
		} else {
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(beginDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = String.format("%s月",DateUtil.format(date, "yyyy年M"));
				trendDataMap.put(monthDate, BigDecimal.ZERO);
			});
		}
		return trendDataMap;
	}

	/**
	 * 封装趋势图数据
	 * @param initDataMap
	 * @param trendData
	 * @return
	 */
	private List<WorkTrendChartVO> handleTrendChartData(String[] initTypeArr,Map<String, BigDecimal> initDataMap, Map<String, Map<String, BigDecimal>> trendData, Integer mode) {
		List<WorkTrendChartVO> trendDataList = new ArrayList<>();
		for (String type : initTypeArr) {
			if (!trendData.containsKey(type)) {
				// 初始化默认数据
				WorkTrendChartVO workTrendChartVO = new WorkTrendChartVO();
				Map<String, BigDecimal> dataMap = ObjectUtil.cloneByStream(initDataMap);
				workTrendChartVO.setType(String.valueOf(type));
				workTrendChartVO.setTrendData(dataMap);
				trendDataList.add(workTrendChartVO);
			}
		}

		trendData.forEach((key, value) -> {
			WorkTrendChartVO workTrendChartVO = new WorkTrendChartVO();
			workTrendChartVO.setType(key);
			Map<String, BigDecimal> dataMap = ObjectUtil.cloneByStream(initDataMap);
			value.forEach((trendKey, trendValue) -> {
				BigDecimal resValue;
				if (mode ==0) {
					resValue = trendValue;
				} else {
					resValue = trendValue.divide(new BigDecimal(60),2, BigDecimal.ROUND_HALF_UP);
				}
				dataMap.put(trendKey, resValue);
			});
			workTrendChartVO.setTrendData(dataMap);
			trendDataList.add(workTrendChartVO);
		});

		return trendDataList;
	}

	/**
	 * 作业汇总-作业工单
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkPieChartVO> chart10(WorkStatisticalDTO params) {
		List<WorkPieChartVO> workPieChartVOList = new ArrayList<>();
		// 作业工单类型
		Integer[] initTypeArr = {MaintainPlanContentEnum.MAINTAIN_BY.getId(), MaintainPlanContentEnum.MAINTAIN_WX.getId(), MaintainPlanContentEnum.MAINTAIN_PARTS.getId()};
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		// 作业工单总数
		long orderTotal = workDayList.stream().map(t -> t.getPlanId()).distinct().count();
		// 类型对应作业工单数
		Map<Integer, Long> workTypeCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getPlanType(), Collectors.mapping(t -> t.getPlanId(),
			Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count()))));
		for (Integer type : initTypeArr) {
			WorkPieChartVO workPieChartVO = new WorkPieChartVO();
			workPieChartVO.setType(String.valueOf(type));
			if (workTypeCountMap.containsKey(type)) {
				workPieChartVO.setOrderCount(workTypeCountMap.get(type));
				BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
				workPieChartVO.setPercentage(percentage);
			} else {
				workPieChartVO.setOrderCount(0L);
				workPieChartVO.setPercentage(BigDecimal.ZERO);
			}
			workPieChartVOList.add(workPieChartVO);
		}

		return workPieChartVOList;
	}

	/**
	 * 作业汇总-作业工单明细-按组
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkOrderDetailVO> chart11(WorkGroupStatisticalDTO params) {
		List<WorkOrderDetailVO> workOrderDetailVOList = new ArrayList<>();
		// 作业工单类型
		Integer[] initTypeArr = {MaintainPlanContentEnum.MAINTAIN_BY.getId(), MaintainPlanContentEnum.MAINTAIN_WX.getId(), MaintainPlanContentEnum.MAINTAIN_PARTS.getId()};
		params.getDeptGroups().forEach(deptGroup -> {
			List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), deptGroup.getUserIds(), null);
			// 作业工单总数
			long orderTotal = workDayList.stream().map(t -> t.getPlanId()).distinct().count();
			// 类型对应作业工单数
			Map<Integer, Long> workTypeCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getPlanType(), Collectors.mapping(t -> t.getPlanId(),
				Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count()))));
			WorkOrderDetailVO workOrderDetailVO = new WorkOrderDetailVO();
			workOrderDetailVO.setName(deptGroup.getDeptName());
			for (Integer type : initTypeArr) {
				if (type == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					//  保养
					if (workTypeCountMap.containsKey(type)) {
						workOrderDetailVO.setByOrderCount(workTypeCountMap.get(type));
						BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
						workOrderDetailVO.setByPercentage(percentage);
					} else {
						workOrderDetailVO.setByOrderCount(0);
						workOrderDetailVO.setByPercentage(BigDecimal.ZERO);
					}
				} else if (type == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					// 维修
					if (workTypeCountMap.containsKey(type)) {
						workOrderDetailVO.setWxOrderCount(workTypeCountMap.get(type));
						BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
						workOrderDetailVO.setWxPercentage(percentage);
					} else {
						workOrderDetailVO.setWxOrderCount(0);
						workOrderDetailVO.setWxPercentage(BigDecimal.ZERO);
					}
				} else {
					if (workTypeCountMap.containsKey(type)) {
						workOrderDetailVO.setPjOrderCount(workTypeCountMap.get(type));
						BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
						workOrderDetailVO.setPjPercentage(percentage);
					} else {
						workOrderDetailVO.setPjOrderCount(0);
						workOrderDetailVO.setPjPercentage(BigDecimal.ZERO);
					}
				}
			}
			workOrderDetailVOList.add(workOrderDetailVO);
		});

		return workOrderDetailVOList;
	}

	/**
	 * 作业汇总-作业工单明细-按人
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkOrderDetailVO> chart12(WorkStatisticalDTO params) {
		List<WorkOrderDetailVO> workOrderDetailVOList = new ArrayList<>();
		List<User> userList = userService.listByIds(params.getUserIds());
		Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getId(), t -> t.getRealName()));
		// key为-1代表全部
		userMap.put(-1L, "全部");
		Long[] initUserArr = userMap.entrySet().stream().map(t -> t.getKey()).toArray(Long[]::new);
		// 作业工单类型
		Integer[] initTypeArr = {MaintainPlanContentEnum.MAINTAIN_BY.getId(), MaintainPlanContentEnum.MAINTAIN_WX.getId(), MaintainPlanContentEnum.MAINTAIN_PARTS.getId()};

		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		// 每个人对应每个类型作业工单数
		Map<Long, Map<Integer,Long>> workOrderUserCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getUserId(), Collectors.groupingBy(t -> t.getPlanType(),
			Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count())))));
		// 汇总 “全部”
		Map<Integer,Long> allWorkOrderCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getPlanType(), Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count()))));
		// key为-1代表全部
		workOrderUserCountMap.put(-1L, allWorkOrderCountMap);
		for (Long userId : initUserArr) {
			WorkOrderDetailVO workOrderDetailVO = new WorkOrderDetailVO();
			workOrderDetailVO.setName(userMap.get(userId));
			if (workOrderUserCountMap.containsKey(userId)) {
				// 类型对应作业工单数
				Map<Integer,Long> workTypeCountMap = workOrderUserCountMap.get(userId);
				// 作业工单总数
				long orderTotal = workTypeCountMap.entrySet().stream().collect(Collectors.summingLong(t -> t.getValue()));
				for (Integer type : initTypeArr) {
					if (type == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
						//  保养
						if (workTypeCountMap.containsKey(type)) {
							workOrderDetailVO.setByOrderCount(workTypeCountMap.get(type));
							BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
							workOrderDetailVO.setByPercentage(percentage);
						} else {
							workOrderDetailVO.setByOrderCount(0);
							workOrderDetailVO.setByPercentage(BigDecimal.ZERO);
						}
					} else if (type == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
						// 维修
						if (workTypeCountMap.containsKey(type)) {
							workOrderDetailVO.setWxOrderCount(workTypeCountMap.get(type));
							BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
							workOrderDetailVO.setWxPercentage(percentage);
						} else {
							workOrderDetailVO.setWxOrderCount(0);
							workOrderDetailVO.setWxPercentage(BigDecimal.ZERO);
						}
					} else {
						if (workTypeCountMap.containsKey(type)) {
							workOrderDetailVO.setPjOrderCount(workTypeCountMap.get(type));
							BigDecimal percentage = new BigDecimal(workTypeCountMap.get(type)).divide(new BigDecimal(orderTotal), 3, BigDecimal.ROUND_HALF_UP);
							workOrderDetailVO.setPjPercentage(percentage);
						} else {
							workOrderDetailVO.setPjOrderCount(0);
							workOrderDetailVO.setPjPercentage(BigDecimal.ZERO);
						}
					}
				}
			}
			workOrderDetailVOList.add(workOrderDetailVO);
		}

		return workOrderDetailVOList;
	}

	/**
	 * 作业汇总-整体趋势--作业工单
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart13(WorkStatisticalDTO params) {
		// 作业工单类型
		String[] initTypeArr = {String.valueOf(MaintainPlanContentEnum.MAINTAIN_BY.getId()), String.valueOf(MaintainPlanContentEnum.MAINTAIN_WX.getId()), String.valueOf(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())};
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		if (!Func.isEmpty(workDayList)) {
			int dimension = params.getDimension();
			if (dimension == 0) {
				// 日
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"), Collectors.mapping(t -> t.getPlanId(),
						Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))));
			} else if (dimension == 1) {
				// 周
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
					}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
				));
			} else {
				// 月
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getPlanType()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s月",DateUtil.format(date, "yyyy年M"));
					}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
				));
			}
		}

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 0);
	}

	/**
	 * 作业汇总-趋势对比--作业工单-按人
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart14(WorkStatisticalDTO params) {
		// 用户集合信息
		List<User> userList = userService.listByIds(params.getUserIds());
		Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getId(), t -> t.getRealName()));
		String[] initTypeArr = userList.stream().map(t -> t.getRealName()).toArray(String[]::new);
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), params.getType());
		if (!Func.isEmpty(workDayList)) {
			int dimension = params.getDimension();
			if (dimension == 0) {
				// 日
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"),
						Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))));
			} else if (dimension == 1) {
				// 周
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
					}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
				));
			} else {
				// 月
				trendData = workDayList.stream().collect(Collectors.groupingBy(t -> userMap.get(t.getUserId()),
					Collectors.groupingBy(t -> {
						Date date = t.getRecordDate();
						return String.format("%s月",DateUtil.format(date, "yyyy年M"));
					}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
				));
			}
		}

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 0);
	}

	/**
	 * 作业汇总-趋势对比--作业工单-按组
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTrendChartVO> chart15(WorkGroupStatisticalDTO params) {
		// 作业工单类型
		String[] initTypeArr = params.getDeptGroups().stream().map(t -> t.getDeptName()).toArray(String[]::new);
		Map<String, BigDecimal> initDataMap = this.initTrendChartData(params.getBeginDate(), params.getEndDate(), params.getDimension());
		Map<String, Map<String, BigDecimal>> trendData = new HashMap<>(4);

		params.getDeptGroups().forEach(deptGroup -> {
			List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), deptGroup.getUserIds(), params.getType());
			if (!Func.isEmpty(workDayList)) {
				Map<String, BigDecimal> workDayTimeMap = null;
				int dimension = params.getDimension();
				if (dimension == 0) {
					// 日
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d"),
						Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count())))));
				} else if (dimension == 1) {
					// 周
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> {
							Date date = t.getRecordDate();
							return String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
						}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
					);
				} else {
					// 月
					workDayTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> {
							Date date = t.getRecordDate();
							return String.format("%s月",DateUtil.format(date, "yyyy年M"));
						}, Collectors.mapping(t -> t.getPlanId(), Collectors.collectingAndThen(Collectors.toSet(), t -> BigDecimal.valueOf(t.stream().count()))))
					);
				}
				trendData.put(deptGroup.getDeptName(), workDayTimeMap);
			}
		});

		return this.handleTrendChartData(initTypeArr, initDataMap, trendData, 0);
	}

	/**
	 * 作业汇总-作业时长明细-按组
	 * @param params
	 * @return
	 */
	@Override
	public List<DeptWorkTimeDetailVO> chart16(WorkGroupStatisticalDTO params) {
		List<DeptWorkTimeDetailVO> deptWorkTimeDetailVOList = new ArrayList<>();
		// 作业工单类型
		Integer[] initTypeArr = {MaintainPlanContentEnum.MAINTAIN_BY.getId(), MaintainPlanContentEnum.MAINTAIN_WX.getId(), MaintainPlanContentEnum.MAINTAIN_PARTS.getId()};
		params.getDeptGroups().forEach(deptGroup -> {
			List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), deptGroup.getUserIds(), null);
			DeptWorkTimeDetailVO deptWorkTimeDetailVO = new DeptWorkTimeDetailVO();
			deptWorkTimeDetailVO.setDeptName(deptGroup.getDeptName());
			if (Func.isEmpty(workDayList)) {
				deptWorkTimeDetailVOList.add(deptWorkTimeDetailVO);
				return;
			}

			// 作业人总数
			long workUserCount = workDayList.stream().map(t -> t.getUserId()).distinct().count();
			deptWorkTimeDetailVO.setWorkUserCount(workUserCount);

			// 每天对应工作时长
			Map<String, Integer> dayWorkTimeMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy-MM-dd"), Collectors.summingInt(t -> t.getWorkHour())));
			// 每天对应作业人数
			Map<String, Long> dayWorkUserCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy-MM-dd"),
				Collectors.mapping(t -> t.getUserId(), Collectors.collectingAndThen(Collectors.toSet(), t -> t.stream().count()))
			));
			// 每天人均耗时
			Map<String, Integer> dayUserTimeMap = new HashMap<>(16);
			dayWorkTimeMap.forEach((key, value) -> {
				// 耗时
				int time = value / Convert.toInt(dayWorkUserCountMap.get(key));
				dayUserTimeMap.put(key, time);
			});
			// 总耗时
			int timeTotal = dayUserTimeMap.entrySet().stream().collect(Collectors.summingInt(t -> t.getValue()));
			/**
			 * 人均每日作业时长:
			 * 人均每日作业时长=每日人均作业时长总和÷实际作业天数;（每日指有作业日）；
			 * 每日人均作业时长=每日各人累计作业时长总和÷每日作业人数；（每日指有作业日）
			 */
			int divUserDayWorkTime = timeTotal / dayUserTimeMap.size();
			deptWorkTimeDetailVO.setDivUserDayWorkTime(divUserDayWorkTime);

			//每人对应实际作业天数
			Map<Long, Long> userWorkDayMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getUserId(),
				Collectors.mapping(t -> t.getRecordDate(), Collectors.collectingAndThen(
					Collectors.toCollection(TreeSet::new),t -> t.stream().count())
				)
			));
			// 每人实际作业天数总和
			long workDayTotal = userWorkDayMap.entrySet().stream().collect(Collectors.summingLong(t -> t.getValue()));
			// 人均作业天数
			BigDecimal divUserWorkDay = new BigDecimal(workDayTotal).divide(new BigDecimal(workUserCount),2, BigDecimal.ROUND_HALF_UP);
			deptWorkTimeDetailVO.setDivUserWorkDayCount(divUserWorkDay);

			// 类型对应累计作业时长
			Map<Integer, Integer> workTimeTypeCountMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getPlanType(), Collectors.summingInt(t -> t.getWorkHour())));
			int totalWorkHour = workTimeTypeCountMap.entrySet().stream().collect(Collectors.summingInt(t -> t.getValue()));
			deptWorkTimeDetailVO.setTotalWorkHour(totalWorkHour);
			for (Integer type : initTypeArr) {
				if (type == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					//  保养
					if (workTimeTypeCountMap.containsKey(type)) {
						deptWorkTimeDetailVO.setByWorkTimeTotal(workTimeTypeCountMap.get(type));
					}
				} else if (type == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					// 维修
					if (workTimeTypeCountMap.containsKey(type)) {
						deptWorkTimeDetailVO.setWxWorkTimeTotal(workTimeTypeCountMap.get(type));
					}
				} else {
					if (workTimeTypeCountMap.containsKey(type)) {
						deptWorkTimeDetailVO.setPjWorkTimeTotal(workTimeTypeCountMap.get(type));
					}
				}
			}
			deptWorkTimeDetailVOList.add(deptWorkTimeDetailVO);
		});

		return deptWorkTimeDetailVOList;
	}

	/**
	 * 作业汇总-作业时长明细-按人
	 * @param params
	 * @return
	 */
	@Override
	public List<WorkTimeDetailVO> chart17(WorkStatisticalDTO params) {
		List<WorkTimeDetailVO> workTimeDetailVOList = new ArrayList<>();
		// 作业工单类型
		Integer[] initTypeArr = {MaintainPlanContentEnum.MAINTAIN_BY.getId(), MaintainPlanContentEnum.MAINTAIN_WX.getId(), MaintainPlanContentEnum.MAINTAIN_PARTS.getId()};
		List<User> userList = userService.listByIds(params.getUserIds());
		Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getId(), t -> t.getRealName()));
		// key为-1代表全部
		userMap.put(-1L, "全部");
		Long[] initUserArr = userMap.entrySet().stream().map(t -> t.getKey()).toArray(Long[]::new);
		List<MaintainPlanUserDayCountVO> workDayList = workStatisticalMapper.selectWorkDayList(params.getBeginDate(), params.getEndDate(), params.getUserIds(), null);
		Map<Long, List<MaintainPlanUserDayCountVO>> workDayMap = workDayList.stream().collect(Collectors.groupingBy(t -> t.getUserId()));
		workDayMap.put(-1L, workDayList);
		for (Long userId : initUserArr) {
			WorkTimeDetailVO workTimeDetailVO = new WorkTimeDetailVO();
			workTimeDetailVO.setName(userMap.get(userId));
			if (!workDayMap.containsKey(userId) || Func.isEmpty(workDayMap.get(userId))) {
				workTimeDetailVOList.add(workTimeDetailVO);
				continue;
			}

			List<MaintainPlanUserDayCountVO> userWorkList = workDayMap.get(userId);
			// 作业天数
			long workDayCount = userWorkList.stream().map(t -> t.getRecordDate()).distinct().count();
			workTimeDetailVO.setWorkDayCount(workDayCount);

			// 作业总时长
			int workTimeTotal = userWorkList.stream().collect(Collectors.summingInt(t -> t.getWorkHour()));
			// 日均作业时长
			int divDayWorkTime = workTimeTotal / Convert.toInt(workDayCount);
			workTimeDetailVO.setDivDayWorkTime(divDayWorkTime);

			// 类型对应作业工时
			Map<Integer, Integer> typeWorkTimeMap = userWorkList.stream().collect(Collectors.groupingBy(t -> t.getPlanType(), Collectors.summingInt(t -> t.getWorkHour())));
			int totalWorkHour = typeWorkTimeMap.entrySet().stream().collect(Collectors.summingInt(t -> t.getValue()));
			workTimeDetailVO.setTotalWorkHour(totalWorkHour);
			for (Integer type : initTypeArr) {
				if (type == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					//  保养
					if (typeWorkTimeMap.containsKey(type)) {
						workTimeDetailVO.setByWorkTimeTotal(typeWorkTimeMap.get(type));
					} else {
						workTimeDetailVO.setByWorkTimeTotal(0);
					}
				} else if (type == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					// 维修
					if (typeWorkTimeMap.containsKey(type)) {
						workTimeDetailVO.setWxWorkTimeTotal(typeWorkTimeMap.get(type));
					} else {
						workTimeDetailVO.setWxWorkTimeTotal(0);
					}
				} else {
					if (typeWorkTimeMap.containsKey(type)) {
						workTimeDetailVO.setPjWorkTimeTotal(typeWorkTimeMap.get(type));
					} else {
						workTimeDetailVO.setPjWorkTimeTotal(0);
					}
				}
			}
			workTimeDetailVOList.add(workTimeDetailVO);
		}

		return workTimeDetailVOList;
	}
}
